<?php
declare(strict_types=1);

namespace Service\MessageService;
use Service\BaseService;
use Hyperf\Amqp\Producer;
use App\Amqp\Producer\SmsMessageProducer;
use Service\Code\Normal;
use Service\ConfigureService\ChannelConfigService;
use App\Model\BbcModel\SmsCode;
use Service\CacheService\CacheProviderService;
use Service\Code\VerifyImgService;

/**
 * 短信服务中心
 * @author chenshubo
 */
class SmsService extends BaseService
{
    const SMS_SEND_TIMES_CODE_CACHE_KEY     = 'bbc_sms_send_times_code';//发送次数
    const SMS_SEND_CODE_CACHE_KEY           = 'bbc_sms_send_code';//发送短信验证
    const SMS_SEND_TIMES_LIMIT              = 3;//发送短信限制
    const SMS_SEND_CACHE_TIME               = 60;//缓存时间
    
    
    public $sms_way = 
    [
        'sms_wwtl'      => 'SmsWwtl',//维网通联
        'sms_chuanglan' => 'SmsChuanglan',//创蓝
    ];
    /**
     * 发送短信验证码
     * @param array $data
     */
    public function sendSms( array $data = [] )
    {
        $cid = $data['cid'];
        $smsWayResult=ChannelConfigService::instance()->getConfig(['code' => 'sms_way','cid'=>$cid]);
        if ( $smsWayResult['code'] == Normal::SUC && $smsWayResult['data']['status'] == 1 && !empty($smsWayResult['data']['value']['type'])){
            $smsWay=$smsWayResult['data']['value']['type'];
        }else{
            $smsWay='sms_wwtl';
        }
        if( !isset($this->sms_way[$smsWay]) ) {
            return Normal::returnCode(Normal::FAIL,"短息发送方式{$smsWay}不支持，请联系管理配置!");
        }
        
        $config=ChannelConfigService::instance()->getConfig(['code' => $smsWay,'cid'=>$cid]);
        if ( $config['code'] != Normal::SUC || empty($config['data']['value']) ){
            return Normal::returnCode(Normal::FAIL,"发送失败,短信未配置");
        }
        
        $sms_way    = ucfirst($this->sms_way[$smsWay]);
        $className  = "Service\VenderClient\Sms\\{$sms_way}Client";
        $callMethod = 'send';
        
        if (!class_exists($className)) {
            return Normal::returnCode(Normal::FAIL, "服务类【{$className}】不存在");
        }
        if (!method_exists($className, $callMethod)) {
            return Normal::returnCode(Normal::FAIL, "服务类【{$className}】方法【{$callMethod}】不存在");
        }
        
        try {
            $pay_result = (new $className($config['data']['value']))->$callMethod($data['mobile'],$data['code'],$data['temp']);
            return $pay_result;
        } catch ( \Throwable $th ) {
            return Normal::returnCode(Normal::FAIL, "短息服务中心异常[{$th->getMessage()},{$th->getFile()},{$th->getLine()}]");
        }
        
        
    }
    
    /**
     * 发送用户短信
     * @param int $cid
     * @param string $mobile
     * @param string $verify_code
     * @param string $temp
     */
    public function sendUserSmsCode(int $cid,string $mobile,string $verify_code,string $temp,string $qrcode_key)
    {
        if ( empty($mobile) ) {
            return Normal::returnCode(Normal::FAIL,"手机号不能为空");
        }
        
        if ( empty($cid) ) {
            return Normal::returnCode(Normal::FAIL,"渠道ID不能为空");
        }
        
        if ( empty($verify_code) ) {
            return Normal::returnCode(Normal::FAIL,"图形验证码不能为空");
        }
        
        if( !checkUserMobileReg($mobile) ) {
            return Normal::returnCode(Normal::FAIL,"手机号码格式不正确，请重新输入");
        }
        
        $check_verify_img  = VerifyImgService::instance()->checkQrCode($qrcode_key,$verify_code);
        if(!$check_verify_img) {
            return Normal::returnCode(Normal::FAIL,"图形验证码验证不通过");
        }
        
        $sms_send_times_cache_key = implode("_",[self::SMS_SEND_TIMES_CODE_CACHE_KEY,$cid,$mobile,$verify_code,$temp]);
        $send_times_cache = CacheProviderService::instance()->getCacheByKey($sms_send_times_cache_key);
        $send_times = $send_times['times'] ?? 0 ;
        if( $send_times >= self::SMS_SEND_TIMES_LIMIT ) {
            return Normal::returnCode(Normal::FAIL,"当前手机号码发送短信过于频繁");
        }
        
        $code = (string)rand(100000,999999);
        //加入发送短信的队列
        $message = [
            'cid'       => $cid,
            'mobile'    => $mobile,
            'code'      => $code,
            'temp'      => 'default'
        ];
        $send_result = $this->publishMsg($message);
        if( $send_result['code'] != Normal::SUC ) {
            return $send_result;
        }
        
        $send_times++;
        
        //写入短信发送成功日志
        $this->addSmsCodeLog($mobile,$code);
        
        //发送次数存入缓存
        CacheProviderService::instance()->cacheBySetKeyValue($sms_send_times_cache_key,['times'=>$send_times],self::SMS_SEND_CACHE_TIME);
        
        
        //设置发送成功短信key
        $sms_send_cache_key = implode("_",[self::SMS_SEND_CODE_CACHE_KEY,$cid,$mobile]);
        CacheProviderService::instance()->cacheBySetKeyValue($sms_send_times_cache_key,['smscode'=>$code],self::SMS_SEND_CACHE_TIME);
        
        //短信校验码发送成功之后，删除图形验证码缓存
        VerifyImgService::instance()->delQrCodeCache($qrcode_key);
        return Normal::returnCode(Normal::SUC,"短信发送成功");
    }
    
    /**
     * 校验短信验证码是否正确
     * @param int $cid
     * @param string $mobile
     * @param string $code
     */
    public function checkSmsCode(int $cid,string $mobile,string $code)
    {
        $key = implode("_",[self::SMS_SEND_CODE_CACHE_KEY,$cid,$mobile]);
        $cache = CacheProviderService::getCacheByKey($key);
        if( empty($cache) ) {
            return Normal::returnCode(Normal::FAIL,"短信校验码已过期，请重新发送!");
        }
        
        if( empty($cache['smscode']) ) {
            return Normal::returnCode(Normal::FAIL,"短信校验码参数缺失，请重新发送!");
        }
        
        if( $cache['smscode'] != $code ) {
            return Normal::returnCode(Normal::FAIL,"短信校验码不正确，请核对之后重新输入!");
        }
        
        CacheProviderService::delCacheSetValue($key);
        return Normal::returnCode(Normal::SUC,"短信校验通过");
    }
    
    /**
     * 增加短信日志
     * @param string $mobile
     * @param string $code
     */
    public function addSmsCodeLog(string $mobile,string $code)
    {
        $data = [
            'mobile' => $mobile,
            'code'   => $code,
            'cd'     => time(),
        ];
        return SmsCode::instance()->add($data);
    }
    
    /**
     * 发布消息队列
     * @param array $msg
     */
    public function publishMsg( array $msg  = [] )
    {
        try {
            $handlerMessage = new SmsMessageProducer($msg);
            $producer = container()->get(Producer::class);
            $result = $producer->produce($handlerMessage,true);
            if( $result ) {
                return Normal::returnCode(Normal::SUC,"发布成功");
            }
            return Normal::returnCode(Normal::FAIL,"操作失败，请稍微再试[100000]");
        } catch ( \Throwable $e ) {
            return Normal::returnCode(Normal::FAIL,"操作失败，请稍微再试[{$e->getMessage()},{$e->getLine()},{$e->getFile()}]");
        }
    }
}
